package com.et.drive.info

import com.et.logger.ELog
import com.et.logger.TAGS
import com.et.machine.convert.IChannelInfo
import com.et.machine.convert.channelGoodsID
import com.et.machine.convert.channelInfo
import com.et.machine.convert.channelPrice
import com.et.util.spiltByteArray
import com.et.util.toBCDInt
import kotlin.experimental.and
import kotlin.math.ceil


data class ChannelInfo(var data: ByteArray) {
    override fun equals(other: Any?): Boolean {
        if (this === other) return true
        if (javaClass != other?.javaClass) return false

        other as ChannelInfo

        if (!data.contentEquals(other.data)) return false

        return true
    }

    override fun hashCode(): Int {
        return data.contentHashCode()
    }

    fun isChannelNormal(channel: Int): Boolean {
        val byte = data[ceil(channel / 8f).toInt()]
        val c = Integer.toBinaryString((byte and 0xFF.toByte()) + 0x100)
        val c1 = c.substring(c.length - 8).toCharArray()[(channel - 1) % 8]
        if (c1 == '1') return true
        return false
    }

    var deviceNumber: Int = data[0].toInt()

    override fun toString(): String {
        val sb = StringBuffer()
        for (i in 1..48) {
            sb.append(" ChannelNormal $i: " + isChannelNormal(i))
        }
        return "ChannelInfo(deviceNumber='$deviceNumber',$sb )"
    }
}

data class ChannelGoodsID(
    var deviceNumber: Int,
    var status: ByteArray,
) {
    override fun equals(other: Any?): Boolean {
        if (this === other) return true
        if (javaClass != other?.javaClass) return false

        other as ChannelGoodsID

        if (deviceNumber != other.deviceNumber) return false
        if (!status.contentEquals(other.status)) return false

        return true
    }

    override fun hashCode(): Int {
        var result = deviceNumber
        result = 31 * result + status.contentHashCode()
        return result
    }

    override fun toString(): String {
        val sb = StringBuffer()
        for (i in 1..48) {
            val s = getGoodsID(i)
            sb.append(" Channel $i Goods ID = '$s', ")
        }
        return "ChannelGoodsID( deviceNumber='$deviceNumber', $sb )"
    }


    private fun getGoodsID(channelID: Int): Any {
        return when (status[channelID - 1].toInt() and 0xFF) {
            0x00 -> "This Channel is not initialize"
            0xFF -> "This Channel is not set goods Id"
            0xEE -> "disable and lock this channel"
            in 0x01..0xFE -> status[channelID - 1].toInt() and 0xFF
            else -> "unknown"
        }
    }
}

data class ChannelPrice(
    var deviceNumber: Int,
    var channelPrices: ByteArray
) {
    override fun equals(other: Any?): Boolean {
        if (this === other) return true
        if (javaClass != other?.javaClass) return false

        other as ChannelPrice

        if (deviceNumber != other.deviceNumber) return false
        if (!channelPrices.contentEquals(other.channelPrices)) return false

        return true
    }

    override fun hashCode(): Int {
        var result = deviceNumber
        result = 31 * result + channelPrices.contentHashCode()
        return result
    }

    override fun toString(): String {
        val sb = StringBuffer()
        for (i in 1..48) {
            sb.append(" Channel '$i' Price: ${getChannelPrice(i - 1)} 角, ")
        }
        return "ChannelPrice( deviceNumber='$deviceNumber', $sb )"
    }

    private fun getChannelPrice(channel: Int): Any {
        return channelPrices.toBCDInt(channel * 2, 2)
    }

}

object IChannelInfoImpl : IChannelInfo {

    private var ChannelGoodsIdCallback: ((ChannelGoodsID) -> Unit)? = null
    override fun channelGoodsIdSubscribe(_callback: (ChannelGoodsID) -> Unit) {
        ChannelGoodsIdCallback = _callback
    }


    fun channelGoodsIDNotify(byteArray: ByteArray) {
        ChannelGoodsIdCallback?.let {
            it(
                ChannelGoodsID(
                    deviceNumber = byteArray[0].toInt(),
                    status = byteArray.spiltByteArray(1, 48)
                ).also {
                    channelGoodsID[it.deviceNumber] = it
                    ELog.d(TAGS.machine, "ChannelGoodsID Info $it")
                }
            )
        }
    }


    private var ChannelInfoCallback: ((ChannelInfo) -> Unit?)? = null
    override fun channelInfoSubscribe(_callback: (ChannelInfo) -> Unit) {
        ChannelInfoCallback = _callback
    }

    fun channelRunningInfoNotify(byteArray: ByteArray) {
        ChannelInfoCallback?.let {
            it(ChannelInfo(byteArray).also {
                channelInfo[it.deviceNumber] = it
                ELog.d(TAGS.machine, "Channel Info $it")
            })
        }
    }


    private var ChannelPriceCallback: ((ChannelPrice) -> Unit?)? = null
    override fun channelPriceSubscribe(_callback: (ChannelPrice) -> Unit) {
        ChannelPriceCallback = _callback
    }

    fun channelPriceNotify(byteArray: ByteArray) {
        ChannelPriceCallback?.let {
            it(
                ChannelPrice(
                    deviceNumber = byteArray[0].toInt(),
                    channelPrices = byteArray.spiltByteArray(1, 96)
                ).also {
                    channelPrice[it.deviceNumber] = it
                    ELog.d(TAGS.machine, "ChannelPrices $it")
                }
            )
        }
    }
}